#include "TcpServer.h"
#include "EventLoop.h"
#include "Acceptor.h"
#include "ThreadPool.h"
#include "Connection.h"
#include "macro.h"

TcpServer::TcpServer() {
  m_main_reactor = std::make_unique<EventLoop>();
  m_acceptor = std::make_unique<Acceptor>(m_main_reactor.get());
  m_acceptor->set_new_connection_callback([this](int fd){
      this->NewConnection(fd);
  });

  unsigned int size = std::thread::hardware_concurrency();
  m_thread_pool = std::make_unique<ThreadPool>(size);

  for (size_t i = 0; i < size; ++i) {
    m_sub_reactors.emplace_back(std::make_unique<EventLoop>());
  }
}



TcpServer::~TcpServer() {}

void TcpServer::Start() {
  for (size_t i = 0; i < m_sub_reactors.size(); ++i) {
    m_thread_pool->Add(&EventLoop::Loop, m_sub_reactors[i].get());
  }
  m_main_reactor->Loop();
}

RC TcpServer::NewConnection(int fd) {
  MYWEB_ASSERT(fd != -1);
  uint64_t random = fd % m_sub_reactors.size();

  std::unique_ptr<Connection> conn = std::make_unique<Connection>(fd, m_sub_reactors[random].get());

  conn->set_delete_connection([this](int fd){
      this->DeleteConnection(fd);
  });
  conn->set_on_recv(m_on_recv_cb);

  m_connections[fd] = std::move(conn);
  if (m_on_connect_cb) {
    m_on_connect_cb(m_connections[fd].get());
  }
  return RC_SUCCESS;
}

RC TcpServer::DeleteConnection(int fd) {
  auto it = m_connections.find(fd);
  MYWEB_ASSERT( it != m_connections.end() );
  m_connections.erase(fd);
  return RC_SUCCESS;
}

void TcpServer::onConnect(std::function<void(Connection *)> fn) { m_on_connect_cb = fn; }

void TcpServer::onRecv(std::function<void(Connection *)> fn) { m_on_recv_cb = fn; }
